package com.rankeiot;

import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Host;
import com.rankeiot.compiler.*;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;

@Mojo(name = "process",defaultPhase = LifecyclePhase.PREPARE_PACKAGE)
public class EasyMojo extends AbstractMojo {
    @Parameter(defaultValue = "${project.build.outputDirectory}/static")
    private File outputDirectory;
    @Parameter(defaultValue = "${project.basedir}/src/main/resources/static")
    private File resourceDir;

    @Parameter(defaultValue = "js/lib/.+$")
    private String excludePath="js/lib/.+$";
    Pattern excludePattern;
    private Map<String,String> outFormatMap =new HashMap<>();
    {
        outFormatMap.put("vue",".js");
        outFormatMap.put("js",".js");
        outFormatMap.put("less",".css");
        outFormatMap.put("css",".css");
    }
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if(!resourceDir.exists()){
            return;
        }
        excludePattern = Pattern.compile(excludePath);
        List<String> sourceFiles= findSource(resourceDir,"");
        if(sourceFiles.size()==0){
            return;
        }
        Log log=getLog();
        Map<String, ICompiler> compilerMap=new HashMap<>();
        for(String f:sourceFiles){

            int idx=f.lastIndexOf(".");
            String ext=f.substring(idx+1);
            File sourceFile=new File(resourceDir,f);
            String outPath=f.replaceFirst("\\."+ext+"$",outFormatMap.get(ext));
            String gzipPath=outPath+".gz";
            log.info("transform:" + f +" ==> "+outPath);
            File out=new File(outputDirectory,outPath);
            File pDir=out.getParentFile();
            if(!pDir.exists()){
                pDir.mkdirs();
            }
            try {
                String source=  Utils.loadText(new FileInputStream(sourceFile));
                ICompiler compiler=compilerMap.get(ext);
                if(compiler==null){
                    switch (ext){
                        case "js":
                            compiler=UglifyCompiler.getInstance();
                            compilerMap.put(ext,compiler);
                            break;
                        case "vue":
                            compiler= VueCompiler.getInstance();
                            compilerMap.put(ext,compiler);
                            break;
                        case "less":
                            compiler=new LessCompiler();
                            compilerMap.put(ext,compiler);
                            break;
                        case "css":
                            compiler=new CssCompiler();
                            compilerMap.put(ext,compiler);
                            break;
                    }
                }
                if(compiler==null){
                    continue;
                }
                try {
                    String outJs = compiler.compile(source);
                    FileWriter fw= new FileWriter(out);
                    fw.write(outJs);
                    fw.flush();
                    fw.close();

                    GZIPOutputStream gzip = new GZIPOutputStream(new FileOutputStream(new File(outputDirectory,gzipPath)));
                    gzip.write(outJs.getBytes());
                    gzip.close();

                }catch (Exception e){
                    getLog().error("Error For:"+f);
                    getLog().error(e);
                }

            } catch (Exception e) {
                getLog().error(e);
            }
        }
        for(ICompiler cp:compilerMap.values()){
            try {
                cp.close();
            } catch (IOException e) {
                getLog().error(e);
            }
        }
        UglifyCompiler.closeInstance();
        VueCompiler.closeInstance();
        try {
            V8Host.getV8Instance().close();
        } catch (JavetException e) {
            e.printStackTrace();
        }
    }
    private List<String> findSource(File file, String path){
        List<String> ret=new ArrayList<>();
        if(excludePattern.matcher(path).find()){
            return ret;
        }
        if(file.isFile()){
            int idx=path.lastIndexOf(".");
            if(idx<=0){
                return ret;
            }
            String ext=path.substring(idx+1);
            String mapExt=outFormatMap.get(ext);
            if(mapExt!=null){
                String outSrcPath=path.replaceFirst("\\."+ext+"$",mapExt);
                String zipPath = outSrcPath+".gz";
                File outF=new File(outputDirectory,zipPath);
                if(!outF.exists()||outF.lastModified()<file.lastModified()){
                    ret.add(path);
                }
            }
            return ret;
        }
        for(File f:file.listFiles()){
            ret.addAll(findSource(f,path+"/"+f.getName()));
        }
        return ret;
    }
}
